001    package net.sf.xdc.processing;
002    
003    /*
004     *  Copyright 2005-2006 Jens Voß.
005     *
006     *  Licensed under the GNU Lesser General Public License (the "License");
007     *  you may not use this file except in compliance with the License.
008     *  You may obtain a copy of the License at
009     *
010     *       http://opensource.org/licenses/lgpl-license.php
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    
019    import java.io.File;
020    import java.io.FileInputStream;
021    import java.io.InputStream;
022    import java.io.IOException;
023    import java.io.FileNotFoundException;
024    import java.io.BufferedReader;
025    import java.io.FileReader;
026    import java.util.Map;
027    import java.util.Properties;
028    import java.util.Enumeration;
029    import java.util.HashMap;
030    import java.util.LinkedHashMap;
031    import java.util.StringTokenizer;
032    import java.util.Iterator;
033    import java.util.regex.Pattern;
034    
035    import org.apache.commons.cli.CommandLine;
036    import org.apache.log4j.Logger;
037    import net.sf.xdc.util.Logging;
038    import net.sf.xdc.util.PathDescriptor;
039    
040    /**
041     * This class is used for determining the XML dialect of an input XML file in
042     * order to be able to apply the correct XSLT stylesheet to the input file.
043     *
044     * @author Jens Voß
045     * @since 0.5
046     * @version 0.5
047     */
048    public class DialectHandler {
049    
050      private static final Logger LOG = Logging.getLogger();
051    
052      private static final String XSL_PACKAGE = "net/sf/xdc/xsl";
053      private static final Map DEFAULTS = new HashMap();
054      private static final Map MAPPINGS = new LinkedHashMap();
055      private static boolean initialized = false;
056    
057      static {
058        DEFAULTS.put("generic", new DialectHandler("generic", XSL_PACKAGE + "/generic.xsl"));
059        DEFAULTS.put("xsl", new DialectHandler("xsl", XSL_PACKAGE + "/xsl.xsl"));
060        DEFAULTS.put("ant", new DialectHandler("ant", XSL_PACKAGE + "/ant.xsl"));
061      }
062    
063      private static void init(CommandLine commandLine) {
064        Properties props = new Properties();
065        if (commandLine.hasOption("dialects")) {
066          InputStream in = null;
067          try {
068            in = new FileInputStream(commandLine.getOptionValue("dialects"));
069            props.load(in);
070            for (Enumeration keys = props.keys(); keys.hasMoreElements();) {
071              String key = (String) keys.nextElement();
072              DEFAULTS.put(key, new DialectHandler(key, props.getProperty(key)));
073            }
074          }
075          catch (FileNotFoundException e) {
076            LOG.error(e.getMessage(), e);
077          }
078          catch (IOException e) {
079            LOG.error(e.getMessage(), e);
080          }
081          finally {
082            try {
083              if (in != null) {
084                in.close();
085              }
086            }
087            catch (IOException e) {
088              LOG.error(e);
089            }
090          }
091        }
092        if (commandLine.hasOption("dialectmapping")) {
093          BufferedReader in = null;
094          try {
095            in = new BufferedReader (new FileReader(commandLine.getOptionValue("dialectmapping")));
096            for (String line = in.readLine(); line != null; line = in.readLine()) {
097              StringTokenizer tok = new StringTokenizer(line, "=", false);
098              MAPPINGS.put(PathDescriptor.convert(tok.nextToken().trim()),
099                           tok.nextToken().trim());
100    
101            }
102          }
103          catch (IOException e) {
104            LOG.error(e.getMessage(), e);
105          }
106          finally {
107            try {
108              if (in != null) {
109                in.close();
110              }
111            }
112            catch (IOException e) {
113              e.printStackTrace();
114            }
115          }
116        }
117        initialized = true;
118      }
119    
120      /**
121       * Static getter method for the correct DialectHandler object.
122       *
123       * @param file The input file for which the correct DialectHandler is
124       *        retrieved
125       * @param packageName
126       * @param commandLine The CommandLine object which may contain additional
127       *        elements controlling which DialectHandler to return
128       * @return The correct DialectHandler for the input file depending on the
129       *         command line settings
130       */
131      public static DialectHandler getDialectHandler(File file,
132                                                     String packageName,
133                                                     CommandLine commandLine) {
134        if (!initialized) {
135          init(commandLine);
136        }
137        String name = getDialect(file, packageName, commandLine);
138        DialectHandler retVal = (DialectHandler) DEFAULTS.get(name);
139        return retVal == null ? (DialectHandler) DEFAULTS.get("generic") : retVal;
140      }
141    
142      private static String getDialect(File file, String packageName,
143                                       CommandLine commandLine) {
144        String filename = packageName != null && packageName.length() != 0 ?
145                          packageName + '/' + file.getName() : file.getName();
146        // check the defined dialectmappings first
147        for (Iterator keys = MAPPINGS.keySet().iterator(); keys.hasNext();) {
148          String regex = (String) keys.next();
149          if (Pattern.matches(regex, filename)) {
150            return (String) MAPPINGS.get(regex);
151          }
152        }
153        // then use the predefined dialect
154        if (commandLine.hasOption("dialect")) {
155          return commandLine.getOptionValue("dialect");
156        }
157        // next try the defaults
158        if ("build.xml".equals(file.getName())) {
159          return "ant";
160        }
161        if (file.getName().endsWith(".xsl")) {
162          return "xsl";
163        }
164        // otherwise 
165        return "generic";
166      }
167    
168      private String name;
169      private String xslResourcePath;
170    
171      /**
172       * Protected constructor. Invoked in static initializer of this class.
173       *
174       * @param name The name of this <code>DialectHandler</code>
175       * @param xslPath The relative path (within the classpath) of this
176       *         <code>DialectHandler</code>
177       */
178      protected DialectHandler(String name, String xslPath) {
179        this.name = name;
180        this.xslResourcePath = xslPath;
181      }
182    
183      /**
184       * Getter method for this <code>DialectHandler</code>'s name.
185       *
186       * @return The name of this <code>DialectHandler</code>
187       */
188      public String getName() {
189        return name;
190      }
191    
192      /**
193       * Getter method for this <code>DialectHandler</code>'s resource path.
194       *
195       * @return The resource path of this <code>DialectHandler</code>
196       */
197      public String getXslResourcePath() {
198        return xslResourcePath;
199      }
200    
201    }